#coding=utf-8

# establish connection


import ADS1256
import DAC8532
import numpy as np
import os

def killport(port):
    command="kill -9 $(netstat -nlp | grep :"+str(port)+" | awk '{print $7}' | awk -F'/' '{{ print $1 }}')"
    os.system(command)

killport(9585)

adc=ADS1256.ADS1256()
dac=DAC8532.DAC8532()
adc.ADS1256_init()

if DAC8532.DAC_VREF!=5:
    DAC8532.DAC_VREF=5.18
    print(f'DAC Vref set to 5.18 V')

def Output(channel,volt,dac=dac):
    volt=volt * 5.0/ 5.188# Calibration

    if channel==1: #channel 0 or channel 1
        dac.DAC8532_Out_Voltage(0x34,volt)
    else:
        dac.DAC8532_Out_Voltage(0x30,volt)

# measure Id while sweeping Vg


print('Data Collection Server Start!')
print('---------------------------')



import asyncio
import websockets

#记录服务器运行状态，等待waiting，运行running，暂停paused，停止stopped
serverStatus = {'stat':'waiting','msg':''} 

async def mainthread(websocket):
    
    import json
    import numpy as np
    import asyncio
    
    global serverStatus
    global adc
    global Output
    
    while True:
        message = ''
        while True:
            await asyncio.sleep(0.05)
            if serverStatus['stat'] == 'running':
                message = serverStatus['msg']
                break        
        if message == '#collect':
            #***************Var Decl. and Init.**************
            AGND = 2.5	# given by the particular LDO 
            drainV = 0.5	# ref AGND
            gateV_begin = -0.8	# ref AGND 
            gateV_end = 2	# ref AGND
            stepV = 0.01	# step volt of sweeping
            stepT = 0.05	# hold time for each step
            settleT = 2		# time before sample
            pinNum_drain = 1	# DAC pinNum giving drainV
            pinNum_source = 0	# ADC pinNum sensing osc 
            pinNum_gate = 0	# DAC pinNum giving gateV
            pinNum_AGND = 1	# ADC pinNum recaliber AGND
            is_sweep_reverse = 0
            do_abs_Id = False
            Vcc = 5
            kR = 1E6

            vd = drainV + AGND
            vg = gateV_begin + AGND
            ftSettle = settleT
            ftHold = stepT
            vmax = gateV_end - gateV_begin
            n = int(vmax / stepV)	#num of samp
            
            rs=[]
            X=[]
            cur_AGND=[]
            Id=[]
            Vg=[]
                    
            #***************Sweep Back**************
            if is_sweep_reverse:
                gateV_begin, gateV_end = gateV_end, gateV_begin
            
            #serv est and basic func
            #global servX
            #serv=servX.hpadb
            Output(pinNum_gate, vg)
            Output(pinNum_drain, vd)
            
            #***************AGND Pre-sampling**************
            
            preAGND = []
            nPreset = int(ftSettle / ftHold)
            for i in range(nPreset):
                r = adc.ADS1256_GetAll()
                preAGND.append(r[pinNum_AGND] * Vcc / 0x7fffff)
                await asyncio.sleep(ftHold)
            
            averAGND = np.mean(preAGND)
            AGND = averAGND
            vd = drainV + AGND
            vg = gateV_begin + AGND
            Output(pinNum_gate, vg)
            Output(pinNum_drain, vd)
            await asyncio.sleep(ftSettle)
            
            lastAGND = AGND
            
            for i in range(n):
                if serverStatus['stat'] == 'stopped':
                    serverStatus['stat'] = 'waiting'
                    break                
                Output(pinNum_drain, drainV + lastAGND)
                Output(pinNum_gate, i * vmax / n + vg)
                X.append(i * vmax / n + gateV_begin)

                r=adc.ADS1256_GetAll()
                rs.append(r[pinNum_source] * Vcc / 0x7fffff)
                Vg.append(r[7] * Vcc / 0x7fffff - AGND)
                cur_AGND.append(r[pinNum_AGND] * Vcc / 0x7fffff)
                lastAGND = cur_AGND[-1]
                await asyncio.sleep(ftHold)
                Id.append((rs[-1] - cur_AGND[-1])*10)
                resp = {}
                resp["type"] = "data"
                resp["value"] = "[{}, {}]".format(X[-1],Id[-1])
                await websocket.send(json.dumps(resp))
                if serverStatus['stat'] == 'paused':
                    while True:
                        await asyncio.sleep(0.05)
                        if serverStatus['stat'] == 'running':
                            break
                        if serverStatus['stat'] == 'stopped':
                            serverStatus['stat'] == 'waiting'
                            break
            #***************Voltage Reset**************
            await asyncio.sleep(ftSettle)
            Output(pinNum_drain, 2.5)
            Output(pinNum_gate, 2.5)
            await asyncio.sleep(ftSettle)
            serverStatus['stat'] = 'waiting'  
        elif message == '#idvt':
            #***************Var Decl. and Init.**************
            AGND = 2.5	# given by the particular LDO 
            drainV = 1.5E-3	# ref AGND
            gateV = 1.205	#ref AGND
            T_begin = 0.0	# ref AGND 
            T_end = 30.0	# ref AGND
            stepT = 0.1	# step volt of sweeping
            settleT = 2		# time before sample
            pinNum_drain = 1	# DAC pinNum giving drainV
            pinNum_source = 0	# ADC pinNum sensing osc 
            pinNum_gate = 0	# DAC pinNum giving gateV
            pinNum_AGND = 1	# ADC pinNum recaliber AGND
            Vcc = 5
            kR = 1E6
            
            vd = drainV + AGND	#drain volt. used for Pi output
            vg = gateV + AGND	#drain volt. used for Pi output
            ftSettle = settleT
            ftHold = stepT
            
            #***************Save**************
            #filename = "/home/pi/Desktop/Pi Test_GYF_ZYY_YHT/2022-02-14/data.txt"
            #fp = open(filename, "a")
            #print(filename, file = fp)
            
            tmax = T_end - T_begin
            n = int(tmax / stepT)	#num of samp
            
            # =======================
            Output(pinNum_gate, vg)
            Output(pinNum_drain, vd)
            
            #***************AGND Pre-sampling**************
            preAGND = []
            nPreset = int(ftSettle / ftHold)
            for i in range(nPreset):
                r = adc.ADS1256_GetAll()
                preAGND.append(r[pinNum_AGND] * Vcc / 0x7fffff)
                await asyncio.sleep(ftHold)
            
            averAGND = np.mean(preAGND)	#mean of the pre-sampled AGND
            AGND = averAGND
            vd = drainV + AGND
            vg = gateV + AGND
            Output(pinNum_gate, vg)
            Output(pinNum_drain, vd)
            await asyncio.sleep(ftSettle)
            
            #***************Sampling**************
            rs=[]
            X=[]
            cur_AGND=[]
            Id=[]
            Vg=[]
            #print('Time', 'Vg', 'AGND', 'Id', sep = '\t')
            i = 0
            while True:
                if serverStatus['stat'] == 'stopped':
                    serverStatus['stat'] = 'waiting'
                    break 
                Output(pinNum_gate, vg)
                X.append(i * tmax / n + T_begin)
                i+=1
                r=adc.ADS1256_GetAll()
                rs.append(r[pinNum_source] * Vcc / 0x7fffff)
                cur_AGND.append(r[pinNum_AGND] * Vcc / 0x7fffff)
                await asyncio.sleep(ftHold)
                Id.append((rs[-1] - cur_AGND[-1]))
                Vg.append(r[2] * Vcc / 0x7fffff)
                #print('%.4f'%(X[-1]), '%.8f'%(Vg[-1]), '%.8f'%(cur_AGND[-1]), '%.8f'%(Id[-1]), sep = '\t', file = fp)

                resp = {}
                resp["type"] = "idvt"
                resp["value"] = "[{}, {}]".format(X[-1],Id[-1]*1000)
                await websocket.send(json.dumps(resp))
                if serverStatus['stat'] == 'paused':
                    while True:
                        await asyncio.sleep(0)
                        if serverStatus['stat'] == 'running':
                            break
                        if serverStatus['stat'] == 'stopped':
                            serverStatus['stat'] == 'waiting'
                            break
            serverStatus['stat'] = 'waiting'  
        else:
            resp = {}
            resp["type"] = "text"
            resp["value"] = message[::-1]
            await websocket.send(json.dumps(resp))
            serverStatus['stat'] = 'waiting'

async def controlthread(websocket):
    global serverStatus
    while True:
        message = await websocket.recv()
        if message == '#stop':
            serverStatus['stat'] = 'stopped'
            serverStatus['msg'] = ''
        elif message == '#pause':
            serverStatus['stat'] = 'paused'
            serverStatus['msg'] = ''
        elif message == '#continue':
            serverStatus['stat'] = 'running'
            serverStatus['msg'] = ''
        else:
            serverStatus['stat'] = 'running'
            serverStatus['msg'] = message

async def echo(websocket, path):
    import asyncio
    global mainthread
    global controlthread
    await asyncio.gather(mainthread(websocket),controlthread(websocket))


asyncio.get_event_loop().run_until_complete(websockets.serve(echo, '0.0.0.0', 9585))
asyncio.get_event_loop().run_forever()

